'''
Created on Jun 26, 2012

@author: daoxuandung
'''


from google.appengine.ext import ndb
from entity import Recipe, Tag
from web import util
import unique
from operator import itemgetter

@ndb.tasklet
def get_similar_score(recipe, tag_keys):
    """
    Algorithm to calculate similarity score
    similarity = 80*common_score + 20*like_score
    """
    
    # Score from how many tags of recipe matched the request
    common_tags = set(tag_keys).intersection(recipe.tags)
    common_score = 80*float(len(common_tags))/float(len(tag_keys))
    
    # Score from how many people like the tags
    recipe_tag_weight = 0
    input_weight = 0
    for tag_key in common_tags:
        tag = yield tag_key.get_async()
        recipe_tag_weight += tag.weight
        
    for tag_key in tag_keys:
        tag = yield tag_key.get_async()
        input_weight += tag.weight
    
    like_score = 20*float(recipe_tag_weight)/float(input_weight)
    
    # Return similarity score
    raise ndb.Return(common_score + like_score)


@ndb.tasklet
def get_by_tags(likes, hates, others):
    # Get recipes by what user likes, hates and others
    like_keys, hate_keys, other_keys = [], [], []
    
    if likes:
        qry = Tag.query(Tag.tag.IN(likes))
        like_keys = yield qry.fetch_async(keys_only=True)
    
    if hates:
        qry = Tag.query(Tag.tag.IN(hates))
        hate_keys = yield qry.fetch_async(keys_only=True)
    
    if others:
        qry = Tag.query(Tag.tag.IN(others))
        other_keys = yield qry.fetch_async(keys_only=True)
    
    # Retrieve recipe from database based on what user likes
    qry = Recipe.query(Recipe.tags.IN(like_keys))
    data = yield qry.fetch_async()
    
    recipe_list = []
    input_tags = unique.unique(like_keys + other_keys)
    
    # Remove the recipe that user hates
    # Calculate similarity score from user likes and others nice to have
    for recipe in data:
        hate_recipes = set(hate_keys).intersection(recipe.tags)
        if len(hate_recipes) > 0:
            pass
        else:            
            recipe_dict = util.ndb_to_dict(recipe)
            recipe_dict['similarity'] = yield get_similar_score(recipe, input_tags)
            recipe_list.append(recipe_dict)
     
    # Sort the result list based on similarity, DESC
    recipe_list = sorted(recipe_list, 
                         key=itemgetter('similarity'), 
                         reverse=True)
    
    # Return
    raise ndb.Return(recipe_list)